package com.phaeton.beemeup.util;

import org.andengine.engine.camera.ZoomCamera;
import org.andengine.engine.handler.IUpdateHandler;
import org.andengine.entity.scene.Scene;
import org.andengine.input.touch.detector.ScrollDetector;
import org.andengine.input.touch.detector.SurfaceScrollDetector;
import org.andengine.input.touch.detector.ScrollDetector.IScrollDetectorListener;

public class SmoothScrollDetector extends SurfaceScrollDetector {

	private static class ScrollListener implements IScrollDetectorListener {

		@Override
		public void onScrollStarted(ScrollDetector pScollDetector,
				int pPointerID, float pDistanceX, float pDistanceY) {
			SmoothScrollDetector smoothScrollDetector = (SmoothScrollDetector) pScollDetector;

			smoothScrollDetector.mScrollAmountX += pDistanceX;
			smoothScrollDetector.mScrollAmountY += pDistanceY;
		}

		@Override
		public void onScroll(ScrollDetector pScollDetector, int pPointerID,
				float pDistanceX, float pDistanceY) {
			SmoothScrollDetector smoothScrollDetector = (SmoothScrollDetector) pScollDetector;

			smoothScrollDetector.mScrollAmountX += pDistanceX;
			smoothScrollDetector.mScrollAmountY += pDistanceY;
		}

		@Override
		public void onScrollFinished(ScrollDetector pScollDetector,
				int pPointerID, float pDistanceX, float pDistanceY) {
			SmoothScrollDetector smoothScrollDetector = (SmoothScrollDetector) pScollDetector;

			smoothScrollDetector.mScrollAmountX += pDistanceX;
			smoothScrollDetector.mScrollAmountY += pDistanceY;
		}

	}

	private final class ScrollUpdater implements IUpdateHandler {
		@Override
		public void onUpdate(float pSecondsElapsed) {
			if (mScrollAmountX == 0 && mScrollAmountY == 0)
				return;

			final float zoomFactor = mCamera.getZoomFactor();

			float xScroll = mScrollAmountX * (pSecondsElapsed * mScrollSpeed);
			float yScroll = mScrollAmountY * (pSecondsElapsed * mScrollSpeed);

			if (Math.abs(xScroll) > Math.abs(mScrollAmountX))
				xScroll = mScrollAmountX;
			if (Math.abs(yScroll) > Math.abs(mScrollAmountY))
				yScroll = mScrollAmountY;

			mCamera.offsetCenter(-xScroll / zoomFactor, -yScroll / zoomFactor);

			mScrollAmountX -= xScroll;
			mScrollAmountY -= yScroll;

			if (Math.abs(mScrollAmountX) < 1)
				mScrollAmountX = 0;
			if (Math.abs(mScrollAmountY) < 1)
				mScrollAmountY = 0;
		}

		@Override
		public void reset() {

		}
	}

	private static final float TRIGGER_SCROLL_MINIMUM_DISTANCE_DEFAULT = 10;
	private static final float SCROLL_SPEED_DEFAULT = 12;

	private ZoomCamera mCamera;
	private Scene mScene;
	private float mScrollSpeed;

	public float mScrollAmountX = 0;
	public float mScrollAmountY = 0;
	private ScrollUpdater mUpdateHandler;

	public SmoothScrollDetector(ZoomCamera camera, Scene scene) {
		this(SmoothScrollDetector.TRIGGER_SCROLL_MINIMUM_DISTANCE_DEFAULT,
				camera, scene, SmoothScrollDetector.SCROLL_SPEED_DEFAULT);
	}

	public SmoothScrollDetector(float pTriggerScrollMinimumDistance,
			ZoomCamera camera, Scene scene, float scrollSpeed) {
		super(pTriggerScrollMinimumDistance, new ScrollListener());
		mCamera = camera;
		mScene = scene;
		mScrollSpeed = scrollSpeed;

		mUpdateHandler = new ScrollUpdater();
		this.enable();
	}

	public void disable() {
		mScene.unregisterUpdateHandler(mUpdateHandler);
	}

	public void enable() {
		mScene.registerUpdateHandler(mUpdateHandler);
	}

}
